Packages

library(plyr)
library(tidyverse)
library(here)
library(geojsonR)
library(janitor)
library(knitr)
library(lubridate) 
library(mapview)
library(gbfs)
library(sf) 
library(tmap)
library(tidycensus)
library(dplyr)
library(conflicted)
library(plotly)
conflicts_prefer(here::here)
conflicts_prefer(dplyr::rename)
conflicts_prefer(dplyr::filter)
conflicts_prefer(dplyr::mutate)

Reading the files.

Metro Station Entrances to map the location of metro, boarding data to show how many people are using the metro station, and bikeshare to show the number of people riding bikes.

All data is from the month September because there are no major holidays, the weather is still decent enough for people to ride bikes, and the number of tourists/ pleasure bike riders are reduced.

For the purpose of this project, we plan on focusing on the commuters, and plan on creating more bike locations to better suit the number of commuters.

metro <- FROM_GeoJson(here('data_raw', 'Metro_Station_Entrances_in_DC.geojson'))
metroRiders <- read.csv(here( 'Boardings by Route Table_Full Data_data.csv'))
metroLoc <- read.csv(here('data_raw', 'Metro_Stations_Regional.csv')) 

sept_raw <- read_csv(here( '202309-capitalbikeshare-tripdata.csv'))

neigh = st_read(here("data_raw", "DC_Health_Planning_Neighborhoods.geojson")) %>% clean_names()

Cleaning Data

This filters the data so we are only getting entries for the weekdays and not the weekends, appending location variables to station names, and combining repeat stations with a summed amount of entries.

#metroLoc = metroLoc |> 
  #rename("X" = "ï..X")

metroAddy <- subset(metroLoc, select = c(NAME, ADDRESS, X, Y))|>
  rename("Station" = "NAME", "Lon" = "X", "Lat" = "Y")

metroRiders$Time.Period = NULL
metroRiders$Day.of.Week = NULL
metroRiders$Holiday = NULL
metroRiders$Month = NULL
metroRiders$Year = NULL
metroRiders$Avg.Daily.Entries.Rounded = NULL

#metroRiders = metroRiders |>
 #rename("Station" = "ï..Station")

metroR1 <- metroRiders |>
  filter(Servicetype == "Weekday") |>
  ddply("Station", numcolwise(sum))

METRO <- merge(x = metroR1, y = metroAddy, by = "Station")

glimpse(METRO)

Cleaning bike data

bikeR1 is the data set originated from September Bikeshare data. It is filtered to keep the columns “started at”, “start lat” and “start_lng”. Na.omit gets rid of everything null, and mutate adds the date to when each bike ride started.

bikeR2 is a further filtering of bikeR1 where coordinates are added so we can map out the bike riders starting location.

bikeR3 is the new data set where bikeR2 and neigh are joined.

bikeR1 = sept_raw %>% select(started_at, start_lat, start_lng) %>% na.omit() %>% mutate(start_date=as.Date(started_at)) %>% select(start_date, start_lat, start_lng)

bikeR2 = bikeR1 %>% st_as_sf(coords=c("start_lng", "start_lat"), crs=4326)

st_crs(neigh$geometry[1])

bikeR3 = bikeR2 %>% st_join(neigh)


 
#code for possible future mapping 
#df1_s_sf = df1_s %>% st_as_sf(coords =c("start_lng", "start_lat"), crs = 4326)

Metro Map

The first part of this code chunk is converting the metro data frame into a spatial data frame.

MetroMap2 is a filtration of MetroMap that joins the data set “neigh” and omits any null values. Then a variable ‘code’ is added to the numcolwise. There are 50 ‘codes’ created in this process. Then from those codes, we will determine rideship for both bikes and metro.

MetroMap <- st_as_sf(METRO, coords = c("Lon", "Lat"), crs =4326)

MetroMap2 <- MetroMap %>%
  st_join(neigh) %>% na.omit() %>%
  ddply("code", numcolwise(sum))

More Filtering

neigh1 is the new data frame of “neigh” where code and geometry are the chosen variables to be kept.

bike R4 is a further filtration of bikeR3, where start date, code, geometry is kept and geometry column is dropped.

bikeR5 is another filter of neigh1, where bikeR4 is added (joined). Additionally, each of the weekend dates are removed from the data set as we chose to only look at weekday data.


neigh1 = neigh %>% select(code, geometry)

bikeR4 = bikeR3 %>% select(start_date, code, geometry) %>% st_drop_geometry()

bikeR5 = neigh1 %>% full_join(bikeR4) %>% filter(start_date != as.Date('2023-09-02')) %>% filter(start_date != as.Date('2023-09-03')) %>% filter(start_date != as.Date('2023-09-09')) %>% filter(start_date != as.Date('2023-09-10')) %>% filter(start_date != as.Date('2023-09-16')) %>% filter(start_date != as.Date('2023-09-17')) %>% filter(start_date != as.Date('2023-09-23')) %>% filter(start_date != as.Date('2023-09-24')) %>% filter(start_date != as.Date('2023-09-30'))

And More!

bikeR6 is a nre data frame where we took the bike data from set bikeR5. bikeR6 has 51 codes and they are listed as observations. All null values are ommitted.

bikeR7 takes the data from bikeR6 and keeps the code as well as frequency and renames it to bike_freq.

#plot(neigh)

bikeR6 = data.frame(table(bikeR5$code)) %>% rename(code=Var1) %>% full_join(bikeR5) %>% select(code, Freq, geometry) %>% distinct() %>% na.omit()

bikeR7 = bikeR6 %>% select (code, Freq) %>% rename(bike_freq = Freq)

MetroMap3 = MetroMap2 %>% select(Entries, code) %>% rename(metro_freq = Entries)

metro_bike_df = bikeR7 %>% full_join(MetroMap3) %>% mutate(metro_freq = replace_na(metro_freq, 0))

#bikeR7 = bikeR5 %>% count(code, start_date)

#plot(bikeR6)

Last One!

bikeR8 takes bikeR6 and keeps the code and frequency. It also creates a column called bike because all the data in this set is from bike riders. We will use this column later when we make our visual.

MetroMap4 continues the filtration of MetroMap2 where entries (later renamed to freq) and code are kept. Every data in this set is given the variable ‘metro’ as they represent a metro rider.

bikeR8 = bikeR6 %>% select (code, Freq) %>% rename(freq = Freq) %>% mutate(transport = 'bike')

MetroMap4 = MetroMap2 %>% select(Entries, code) %>% rename(freq = Entries) %>% mutate(transport = 'metro')

code = c("N1", "N10", "N11", "N14", "N15", "N16", "N2", "N20", "N21", "N22", "N26", "N27", "N28", "N3", "N32", "N33", "N34", "N36", "N37", "N4", "N40", "N41", "N45", "N46", "N47", "N49", "N5", "N50", "N51", "N6", "N8")

freq = c(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)

transport = c('metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro', 'metro')

metroExtra = data.frame(code, freq, transport)

MetroMap4 = MetroMap4 %>% rbind(metroExtra)

metro_bike_df2 = bikeR8 %>% full_join(MetroMap4)

Mapping Metro

This is a simple visual of the metro station locations in DC.

entrances=st_read(here("Metro_Station_Entrances_in_DC.geojson")) %>% clean_names()

class(entrances)

plot(entrances)

Mapping Bike Data

We create a gg plot of the data from above. The combined data set of metro and bike riders (metro_bike_df2). We wanted to visualize the number of people who are riding the metro vs using bikes in each of the ‘codes’.

charts <- ggplot(metro_bike_df2, aes(fill=transport, y=freq, x=code)) + geom_bar(position='dodge', stat='identity')

ggplotly(charts)

Recommednation:

Based on the data comparisons of metro entries and bike entries, we would recommend that the bikeshare group look into increasing the amount of bike stations in neighborhoods: n2, n5, n22, n28, n41 as these are the neighborhoods with no metro stations being entered and already have a solid group of bike riders, so increasing stations here would allow ofr the most benefits for the bikeshare.

LS0tDQp0aXRsZTogIkZpbmFsIFByb2plY3QiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIyBQYWNrYWdlcw0KDQpgYGB7cn0NCmxpYnJhcnkocGx5cikNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShoZXJlKQ0KbGlicmFyeShnZW9qc29uUikNCmxpYnJhcnkoamFuaXRvcikNCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkgDQpsaWJyYXJ5KG1hcHZpZXcpDQpsaWJyYXJ5KGdiZnMpDQpsaWJyYXJ5KHNmKSANCmxpYnJhcnkodG1hcCkNCmxpYnJhcnkodGlkeWNlbnN1cykNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGNvbmZsaWN0ZWQpDQpsaWJyYXJ5KHBsb3RseSkNCmNvbmZsaWN0c19wcmVmZXIoaGVyZTo6aGVyZSkNCmNvbmZsaWN0c19wcmVmZXIoZHBseXI6OnJlbmFtZSkNCmNvbmZsaWN0c19wcmVmZXIoZHBseXI6OmZpbHRlcikNCmNvbmZsaWN0c19wcmVmZXIoZHBseXI6Om11dGF0ZSkNCg0KYGBgDQoNCiMjIFJlYWRpbmcgdGhlIGZpbGVzLg0KDQpNZXRybyBTdGF0aW9uIEVudHJhbmNlcyB0byBtYXAgdGhlIGxvY2F0aW9uIG9mIG1ldHJvLCBib2FyZGluZyBkYXRhIHRvIHNob3cgaG93IG1hbnkgcGVvcGxlIGFyZSB1c2luZyB0aGUgbWV0cm8gc3RhdGlvbiwgYW5kIGJpa2VzaGFyZSB0byBzaG93IHRoZSBudW1iZXIgb2YgcGVvcGxlIHJpZGluZyBiaWtlcy4NCg0KQWxsIGRhdGEgaXMgZnJvbSB0aGUgbW9udGggU2VwdGVtYmVyIGJlY2F1c2UgdGhlcmUgYXJlIG5vIG1ham9yIGhvbGlkYXlzLCB0aGUgd2VhdGhlciBpcyBzdGlsbCBkZWNlbnQgZW5vdWdoIGZvciBwZW9wbGUgdG8gcmlkZSBiaWtlcywgYW5kIHRoZSBudW1iZXIgb2YgdG91cmlzdHMvIHBsZWFzdXJlIGJpa2UgcmlkZXJzIGFyZSByZWR1Y2VkLg0KDQpGb3IgdGhlIHB1cnBvc2Ugb2YgdGhpcyBwcm9qZWN0LCB3ZSBwbGFuIG9uIGZvY3VzaW5nIG9uIHRoZSBjb21tdXRlcnMsIGFuZCBwbGFuIG9uIGNyZWF0aW5nIG1vcmUgYmlrZSBsb2NhdGlvbnMgdG8gYmV0dGVyIHN1aXQgdGhlIG51bWJlciBvZiBjb21tdXRlcnMuDQoNCmBgYHtyfQ0KbWV0cm8gPC0gRlJPTV9HZW9Kc29uKGhlcmUoJ2RhdGFfcmF3JywgJ01ldHJvX1N0YXRpb25fRW50cmFuY2VzX2luX0RDLmdlb2pzb24nKSkNCm1ldHJvUmlkZXJzIDwtIHJlYWQuY3N2KGhlcmUoICdCb2FyZGluZ3MgYnkgUm91dGUgVGFibGVfRnVsbCBEYXRhX2RhdGEuY3N2JykpDQptZXRyb0xvYyA8LSByZWFkLmNzdihoZXJlKCdkYXRhX3JhdycsICdNZXRyb19TdGF0aW9uc19SZWdpb25hbC5jc3YnKSkgDQoNCnNlcHRfcmF3IDwtIHJlYWRfY3N2KGhlcmUoICcyMDIzMDktY2FwaXRhbGJpa2VzaGFyZS10cmlwZGF0YS5jc3YnKSkNCg0KbmVpZ2ggPSBzdF9yZWFkKGhlcmUoImRhdGFfcmF3IiwgIkRDX0hlYWx0aF9QbGFubmluZ19OZWlnaGJvcmhvb2RzLmdlb2pzb24iKSkgJT4lIGNsZWFuX25hbWVzKCkNCg0KYGBgDQoNCiMjIENsZWFuaW5nIERhdGENCg0KVGhpcyBmaWx0ZXJzIHRoZSBkYXRhIHNvIHdlIGFyZSBvbmx5IGdldHRpbmcgZW50cmllcyBmb3IgdGhlIHdlZWtkYXlzIGFuZCBub3QgdGhlIHdlZWtlbmRzLCBhcHBlbmRpbmcgbG9jYXRpb24gdmFyaWFibGVzIHRvIHN0YXRpb24gbmFtZXMsIGFuZCBjb21iaW5pbmcgcmVwZWF0IHN0YXRpb25zIHdpdGggYSBzdW1tZWQgYW1vdW50IG9mIGVudHJpZXMuDQoNCmBgYHtyfQ0KI21ldHJvTG9jID0gbWV0cm9Mb2MgfD4gDQogICNyZW5hbWUoIlgiID0gIsOvLi5YIikNCg0KbWV0cm9BZGR5IDwtIHN1YnNldChtZXRyb0xvYywgc2VsZWN0ID0gYyhOQU1FLCBBRERSRVNTLCBYLCBZKSl8Pg0KICByZW5hbWUoIlN0YXRpb24iID0gIk5BTUUiLCAiTG9uIiA9ICJYIiwgIkxhdCIgPSAiWSIpDQoNCm1ldHJvUmlkZXJzJFRpbWUuUGVyaW9kID0gTlVMTA0KbWV0cm9SaWRlcnMkRGF5Lm9mLldlZWsgPSBOVUxMDQptZXRyb1JpZGVycyRIb2xpZGF5ID0gTlVMTA0KbWV0cm9SaWRlcnMkTW9udGggPSBOVUxMDQptZXRyb1JpZGVycyRZZWFyID0gTlVMTA0KbWV0cm9SaWRlcnMkQXZnLkRhaWx5LkVudHJpZXMuUm91bmRlZCA9IE5VTEwNCg0KI21ldHJvUmlkZXJzID0gbWV0cm9SaWRlcnMgfD4NCiAjcmVuYW1lKCJTdGF0aW9uIiA9ICLDry4uU3RhdGlvbiIpDQoNCm1ldHJvUjEgPC0gbWV0cm9SaWRlcnMgfD4NCiAgZmlsdGVyKFNlcnZpY2V0eXBlID09ICJXZWVrZGF5IikgfD4NCiAgZGRwbHkoIlN0YXRpb24iLCBudW1jb2x3aXNlKHN1bSkpDQoNCk1FVFJPIDwtIG1lcmdlKHggPSBtZXRyb1IxLCB5ID0gbWV0cm9BZGR5LCBieSA9ICJTdGF0aW9uIikNCg0KZ2xpbXBzZShNRVRSTykNCg0KYGBgDQoNCiMjIENsZWFuaW5nIGJpa2UgZGF0YQ0KDQpiaWtlUjEgaXMgdGhlIGRhdGEgc2V0IG9yaWdpbmF0ZWQgZnJvbSBTZXB0ZW1iZXIgQmlrZXNoYXJlIGRhdGEuIEl0IGlzIGZpbHRlcmVkIHRvIGtlZXAgdGhlIGNvbHVtbnMgInN0YXJ0ZWQgYXQiLCAic3RhcnQgbGF0IiBhbmQgInN0YXJ0X2xuZyIuIE5hLm9taXQgZ2V0cyByaWQgb2YgZXZlcnl0aGluZyBudWxsLCBhbmQgbXV0YXRlIGFkZHMgdGhlIGRhdGUgdG8gd2hlbiBlYWNoIGJpa2UgcmlkZSBzdGFydGVkLg0KDQpiaWtlUjIgaXMgYSBmdXJ0aGVyIGZpbHRlcmluZyBvZiBiaWtlUjEgd2hlcmUgY29vcmRpbmF0ZXMgYXJlIGFkZGVkIHNvIHdlIGNhbiBtYXAgb3V0IHRoZSBiaWtlIHJpZGVycyBzdGFydGluZyBsb2NhdGlvbi4NCg0KYmlrZVIzIGlzIHRoZSBuZXcgZGF0YSBzZXQgd2hlcmUgYmlrZVIyIGFuZCBuZWlnaCBhcmUgam9pbmVkLiANCg0KYGBge3J9DQpiaWtlUjEgPSBzZXB0X3JhdyAlPiUgc2VsZWN0KHN0YXJ0ZWRfYXQsIHN0YXJ0X2xhdCwgc3RhcnRfbG5nKSAlPiUgbmEub21pdCgpICU+JSBtdXRhdGUoc3RhcnRfZGF0ZT1hcy5EYXRlKHN0YXJ0ZWRfYXQpKSAlPiUgc2VsZWN0KHN0YXJ0X2RhdGUsIHN0YXJ0X2xhdCwgc3RhcnRfbG5nKQ0KDQpiaWtlUjIgPSBiaWtlUjEgJT4lIHN0X2FzX3NmKGNvb3Jkcz1jKCJzdGFydF9sbmciLCAic3RhcnRfbGF0IiksIGNycz00MzI2KQ0KDQpzdF9jcnMobmVpZ2gkZ2VvbWV0cnlbMV0pDQoNCmJpa2VSMyA9IGJpa2VSMiAlPiUgc3Rfam9pbihuZWlnaCkNCg0KDQogDQojY29kZSBmb3IgcG9zc2libGUgZnV0dXJlIG1hcHBpbmcgDQojZGYxX3Nfc2YgPSBkZjFfcyAlPiUgc3RfYXNfc2YoY29vcmRzID1jKCJzdGFydF9sbmciLCAic3RhcnRfbGF0IiksIGNycyA9IDQzMjYpDQpgYGANCg0KDQojIyBNZXRybyBNYXANCg0KVGhlIGZpcnN0IHBhcnQgb2YgdGhpcyBjb2RlIGNodW5rIGlzIGNvbnZlcnRpbmcgdGhlIG1ldHJvIGRhdGEgZnJhbWUgaW50byBhIHNwYXRpYWwgZGF0YSBmcmFtZS4gDQoNCk1ldHJvTWFwMiBpcyBhIGZpbHRyYXRpb24gb2YgTWV0cm9NYXAgdGhhdCBqb2lucyB0aGUgZGF0YSBzZXQgIm5laWdoIiBhbmQgb21pdHMgYW55IG51bGwgdmFsdWVzLiBUaGVuIGEgdmFyaWFibGUgJ2NvZGUnIGlzIGFkZGVkIHRvIHRoZSBudW1jb2x3aXNlLiBUaGVyZSBhcmUgNTAgJ2NvZGVzJyBjcmVhdGVkIGluIHRoaXMgcHJvY2Vzcy4gVGhlbiBmcm9tIHRob3NlIGNvZGVzLCB3ZSB3aWxsIGRldGVybWluZSByaWRlc2hpcCBmb3IgYm90aCBiaWtlcyBhbmQgbWV0cm8uDQoNCmBgYHtyfQ0KTWV0cm9NYXAgPC0gc3RfYXNfc2YoTUVUUk8sIGNvb3JkcyA9IGMoIkxvbiIsICJMYXQiKSwgY3JzID00MzI2KQ0KDQpNZXRyb01hcDIgPC0gTWV0cm9NYXAgJT4lDQogIHN0X2pvaW4obmVpZ2gpICU+JSBuYS5vbWl0KCkgJT4lDQogIGRkcGx5KCJjb2RlIiwgbnVtY29sd2lzZShzdW0pKQ0KYGBgDQoNCg0KIyMgTW9yZSBGaWx0ZXJpbmcNCg0KbmVpZ2gxIGlzIHRoZSBuZXcgZGF0YSBmcmFtZSBvZiAibmVpZ2giIHdoZXJlIGNvZGUgYW5kIGdlb21ldHJ5IGFyZSB0aGUgY2hvc2VuIHZhcmlhYmxlcyB0byBiZSBrZXB0Lg0KDQpiaWtlIFI0IGlzIGEgZnVydGhlciBmaWx0cmF0aW9uIG9mIGJpa2VSMywgd2hlcmUgc3RhcnQgZGF0ZSwgY29kZSwgZ2VvbWV0cnkgaXMga2VwdCBhbmQgZ2VvbWV0cnkgY29sdW1uIGlzIGRyb3BwZWQuDQoNCmJpa2VSNSBpcyBhbm90aGVyIGZpbHRlciBvZiBuZWlnaDEsIHdoZXJlIGJpa2VSNCBpcyBhZGRlZCAoam9pbmVkKS4gQWRkaXRpb25hbGx5LCBlYWNoIG9mIHRoZSB3ZWVrZW5kIGRhdGVzIGFyZSByZW1vdmVkIGZyb20gdGhlIGRhdGEgc2V0IGFzIHdlIGNob3NlIHRvIG9ubHkgbG9vayBhdCB3ZWVrZGF5IGRhdGEuDQoNCmBgYHtyfQ0KDQpuZWlnaDEgPSBuZWlnaCAlPiUgc2VsZWN0KGNvZGUsIGdlb21ldHJ5KQ0KDQpiaWtlUjQgPSBiaWtlUjMgJT4lIHNlbGVjdChzdGFydF9kYXRlLCBjb2RlLCBnZW9tZXRyeSkgJT4lIHN0X2Ryb3BfZ2VvbWV0cnkoKQ0KDQpiaWtlUjUgPSBuZWlnaDEgJT4lIGZ1bGxfam9pbihiaWtlUjQpICU+JSBmaWx0ZXIoc3RhcnRfZGF0ZSAhPSBhcy5EYXRlKCcyMDIzLTA5LTAyJykpICU+JSBmaWx0ZXIoc3RhcnRfZGF0ZSAhPSBhcy5EYXRlKCcyMDIzLTA5LTAzJykpICU+JSBmaWx0ZXIoc3RhcnRfZGF0ZSAhPSBhcy5EYXRlKCcyMDIzLTA5LTA5JykpICU+JSBmaWx0ZXIoc3RhcnRfZGF0ZSAhPSBhcy5EYXRlKCcyMDIzLTA5LTEwJykpICU+JSBmaWx0ZXIoc3RhcnRfZGF0ZSAhPSBhcy5EYXRlKCcyMDIzLTA5LTE2JykpICU+JSBmaWx0ZXIoc3RhcnRfZGF0ZSAhPSBhcy5EYXRlKCcyMDIzLTA5LTE3JykpICU+JSBmaWx0ZXIoc3RhcnRfZGF0ZSAhPSBhcy5EYXRlKCcyMDIzLTA5LTIzJykpICU+JSBmaWx0ZXIoc3RhcnRfZGF0ZSAhPSBhcy5EYXRlKCcyMDIzLTA5LTI0JykpICU+JSBmaWx0ZXIoc3RhcnRfZGF0ZSAhPSBhcy5EYXRlKCcyMDIzLTA5LTMwJykpDQpgYGANCiMjIEFuZCBNb3JlIQ0KDQpiaWtlUjYgaXMgYSBucmUgZGF0YSBmcmFtZSB3aGVyZSB3ZSB0b29rIHRoZSBiaWtlIGRhdGEgZnJvbSBzZXQgYmlrZVI1LiBiaWtlUjYgaGFzIDUxIGNvZGVzIGFuZCB0aGV5IGFyZSBsaXN0ZWQgYXMgb2JzZXJ2YXRpb25zLiBBbGwgbnVsbCB2YWx1ZXMgYXJlIG9tbWl0dGVkLg0KDQpiaWtlUjcgdGFrZXMgdGhlIGRhdGEgZnJvbSBiaWtlUjYgYW5kIGtlZXBzIHRoZSBjb2RlIGFzIHdlbGwgYXMgZnJlcXVlbmN5IGFuZCByZW5hbWVzIGl0IHRvIGJpa2VfZnJlcS4gDQoNCmBgYHtyfQ0KI3Bsb3QobmVpZ2gpDQoNCmJpa2VSNiA9IGRhdGEuZnJhbWUodGFibGUoYmlrZVI1JGNvZGUpKSAlPiUgcmVuYW1lKGNvZGU9VmFyMSkgJT4lIGZ1bGxfam9pbihiaWtlUjUpICU+JSBzZWxlY3QoY29kZSwgRnJlcSwgZ2VvbWV0cnkpICU+JSBkaXN0aW5jdCgpICU+JSBuYS5vbWl0KCkNCg0KYmlrZVI3ID0gYmlrZVI2ICU+JSBzZWxlY3QgKGNvZGUsIEZyZXEpICU+JSByZW5hbWUoYmlrZV9mcmVxID0gRnJlcSkNCg0KTWV0cm9NYXAzID0gTWV0cm9NYXAyICU+JSBzZWxlY3QoRW50cmllcywgY29kZSkgJT4lIHJlbmFtZShtZXRyb19mcmVxID0gRW50cmllcykNCg0KbWV0cm9fYmlrZV9kZiA9IGJpa2VSNyAlPiUgZnVsbF9qb2luKE1ldHJvTWFwMykgJT4lIG11dGF0ZShtZXRyb19mcmVxID0gcmVwbGFjZV9uYShtZXRyb19mcmVxLCAwKSkNCg0KI2Jpa2VSNyA9IGJpa2VSNSAlPiUgY291bnQoY29kZSwgc3RhcnRfZGF0ZSkNCg0KI3Bsb3QoYmlrZVI2KQ0KYGBgDQojIyBMYXN0IE9uZSENCg0KYmlrZVI4IHRha2VzIGJpa2VSNiBhbmQga2VlcHMgdGhlIGNvZGUgYW5kIGZyZXF1ZW5jeS4gSXQgYWxzbyBjcmVhdGVzIGEgY29sdW1uIGNhbGxlZCBiaWtlIGJlY2F1c2UgYWxsIHRoZSBkYXRhIGluIHRoaXMgc2V0IGlzIGZyb20gYmlrZSByaWRlcnMuIFdlIHdpbGwgdXNlIHRoaXMgY29sdW1uIGxhdGVyIHdoZW4gd2UgbWFrZSBvdXIgdmlzdWFsLiANCg0KTWV0cm9NYXA0IGNvbnRpbnVlcyB0aGUgZmlsdHJhdGlvbiBvZiBNZXRyb01hcDIgd2hlcmUgZW50cmllcyAobGF0ZXIgcmVuYW1lZCB0byBmcmVxKSBhbmQgY29kZSBhcmUga2VwdC4gRXZlcnkgZGF0YSBpbiB0aGlzIHNldCBpcyBnaXZlbiB0aGUgdmFyaWFibGUgJ21ldHJvJyBhcyB0aGV5IHJlcHJlc2VudCBhIG1ldHJvIHJpZGVyLg0KDQpgYGB7cn0NCmJpa2VSOCA9IGJpa2VSNiAlPiUgc2VsZWN0IChjb2RlLCBGcmVxKSAlPiUgcmVuYW1lKGZyZXEgPSBGcmVxKSAlPiUgbXV0YXRlKHRyYW5zcG9ydCA9ICdiaWtlJykNCg0KTWV0cm9NYXA0ID0gTWV0cm9NYXAyICU+JSBzZWxlY3QoRW50cmllcywgY29kZSkgJT4lIHJlbmFtZShmcmVxID0gRW50cmllcykgJT4lIG11dGF0ZSh0cmFuc3BvcnQgPSAnbWV0cm8nKQ0KDQpjb2RlID0gYygiTjEiLCAiTjEwIiwgIk4xMSIsICJOMTQiLCAiTjE1IiwgIk4xNiIsICJOMiIsICJOMjAiLCAiTjIxIiwgIk4yMiIsICJOMjYiLCAiTjI3IiwgIk4yOCIsICJOMyIsICJOMzIiLCAiTjMzIiwgIk4zNCIsICJOMzYiLCAiTjM3IiwgIk40IiwgIk40MCIsICJONDEiLCAiTjQ1IiwgIk40NiIsICJONDciLCAiTjQ5IiwgIk41IiwgIk41MCIsICJONTEiLCAiTjYiLCAiTjgiKQ0KDQpmcmVxID0gYygwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwKQ0KDQp0cmFuc3BvcnQgPSBjKCdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycsICdtZXRybycpDQoNCm1ldHJvRXh0cmEgPSBkYXRhLmZyYW1lKGNvZGUsIGZyZXEsIHRyYW5zcG9ydCkNCg0KTWV0cm9NYXA0ID0gTWV0cm9NYXA0ICU+JSByYmluZChtZXRyb0V4dHJhKQ0KDQptZXRyb19iaWtlX2RmMiA9IGJpa2VSOCAlPiUgZnVsbF9qb2luKE1ldHJvTWFwNCkNCg0KYGBgDQoNCg0KIyMgTWFwcGluZyBNZXRybw0KDQpUaGlzIGlzIGEgc2ltcGxlIHZpc3VhbCBvZiB0aGUgbWV0cm8gc3RhdGlvbiBsb2NhdGlvbnMgaW4gREMuDQoNCmBgYHtyfQ0KZW50cmFuY2VzPXN0X3JlYWQoaGVyZSgiTWV0cm9fU3RhdGlvbl9FbnRyYW5jZXNfaW5fREMuZ2VvanNvbiIpKSAlPiUgY2xlYW5fbmFtZXMoKQ0KDQpjbGFzcyhlbnRyYW5jZXMpDQoNCnBsb3QoZW50cmFuY2VzKQ0KYGBgDQoNCiMjIE1hcHBpbmcgQmlrZSBEYXRhDQoNCldlIGNyZWF0ZSBhIGdnIHBsb3Qgb2YgdGhlIGRhdGEgZnJvbSBhYm92ZS4gVGhlIGNvbWJpbmVkIGRhdGEgc2V0IG9mIG1ldHJvIGFuZCBiaWtlIHJpZGVycyAobWV0cm9fYmlrZV9kZjIpLiBXZSB3YW50ZWQgdG8gdmlzdWFsaXplIHRoZSBudW1iZXIgb2YgcGVvcGxlIHdobyBhcmUgcmlkaW5nIHRoZSBtZXRybyB2cyB1c2luZyBiaWtlcyBpbiBlYWNoIG9mIHRoZSAnY29kZXMnLiANCg0KYGBge3J9DQpjaGFydHMgPC0gZ2dwbG90KG1ldHJvX2Jpa2VfZGYyLCBhZXMoZmlsbD10cmFuc3BvcnQsIHk9ZnJlcSwgeD1jb2RlKSkgKyBnZW9tX2Jhcihwb3NpdGlvbj0nZG9kZ2UnLCBzdGF0PSdpZGVudGl0eScpDQoNCmdncGxvdGx5KGNoYXJ0cykNCmBgYA0KDQojIyBSZWNvbW1lZG5hdGlvbjoNCkJhc2VkIG9uIHRoZSBkYXRhIGNvbXBhcmlzb25zIG9mIG1ldHJvIGVudHJpZXMgYW5kIGJpa2UgZW50cmllcywgd2Ugd291bGQgcmVjb21tZW5kIHRoYXQgdGhlIGJpa2VzaGFyZSBncm91cCBsb29rIGludG8gaW5jcmVhc2luZyB0aGUgYW1vdW50IG9mIGJpa2Ugc3RhdGlvbnMgaW4gbmVpZ2hib3Job29kczogbjIsIG41LCBuMjIsIG4yOCwgbjQxIGFzIHRoZXNlIGFyZSB0aGUgbmVpZ2hib3Job29kcyB3aXRoIG5vIG1ldHJvIHN0YXRpb25zIGJlaW5nIGVudGVyZWQgYW5kIGFscmVhZHkgaGF2ZSBhIHNvbGlkIGdyb3VwIG9mIGJpa2UgcmlkZXJzLCBzbyBpbmNyZWFzaW5nIHN0YXRpb25zIGhlcmUgd291bGQgYWxsb3cgb2ZyIHRoZSBtb3N0IGJlbmVmaXRzIGZvciB0aGUgYmlrZXNoYXJlLg==